/*
 *  MidiParser.h
 *  MusicAnalyzer
 *
 *  Created by jiro on 12/03/30.
 *  Copyright 2012 jiro music. All rights reserved.
 *
 */

#pragma once

#include <queue>

#include "MidiMessage.h"

namespace sc
{
	class MidiParser
	{
	public:

		enum ParseOption
		{
			/*	@remark kind of midi device send four byte message even it's enough three bytes, and first byte is status left 4 bit.
			//	example: following case will happen.
				Channel One Note On is
					0x91 0x3f 0x54
				but data is actually
					0x09 0x91 0x3f 0x54			*/
			Option_RegardFirstByteAsLeftFourBitsOfStatusByte,
			Option_One = Option_RegardFirstByteAsLeftFourBitsOfStatusByte,		//	to shorthand for programmar

			Option_None,
		};

	public:

		MidiParser( ParseOption option );

		~MidiParser();

		/**	@brief parse midi bytes and get const MidiMessage* that managed by caller.
				caller shoule return disused MidiMessage* to PoolAllocator< MidiMessage >.
		*/
		bool Parse( uint8_t* bytes, int byteCount, std::queue< const MidiMessage* >& messages )
		{
			return (this->*parseFuncPtr)( bytes, byteCount, messages );
		} 

		void AddObserfer( void* instance, void* (*notify)(void*) );

	private:

		bool ParseWithoutOption( uint8_t* midiBytesPtr, int byteCount, std::queue< const MidiMessage* >& messages );

		bool ParseWithOptionOne( uint8_t* midiBytesPtr, int byteCount, std::queue< const MidiMessage* >& messages );

		MidiMessage* GetChannelMidiMessage( int dataByteCount, MidiMessage::Type type, uint8_t channel, uint8_t* dataBytePtr );

		MidiMessage* GetSystemMidiMessage( int dataByteCount, MidiMessage::Type type, uint8_t* dataBytePtr );

		void Notify() const;

	private:

		ParseOption option;

		bool (MidiParser::*parseFuncPtr)( uint8_t*, int, std::queue< const MidiMessage* >& );

		std::vector< MidiMessage* > parsedMidiMessage;		//	memorize to release instance

	};

}
